home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_09_05
/
9n05105a
< prev
next >
Wrap
Text File
|
1991-03-19
|
9KB
|
285 lines
struct input {
double s0[6]; // s0[6]: Pos/vel at time t0
double tau; // Time interval from t0 to t
double mu; // Mu from diff. eq. of motion
double psi; // Initial approx for sol. of
// Kepler's equation.
} ;
struct output {
double s[6]; // s[6]: Pos/vel at time t.
} ;
twobdy(struct input *in, struct output *out)
// twobdy: A function to compute the position and
// velocity of an orbiting body under
// two-body motion, given the position and
// velocity at time t0, the elapsed time tau
// at which to compute the solution, the value
// for mu for the two bodies, and an initial
// approximation psi of the solution to
// the generalized Kepler's equation.
//
// References:
// (1) Goodyear, W.H.,"A General Method for the
// Computation of Cartesian Coordinates and
// Partial Derivatives of the Two-Body Problem",
// NASA Contractor Report NASA CR 522.
// (2) Bate, Mueller, White, Fundamentals of
// Astrodynamics.
{
#define SQ(x) (x*x)
#define LARGENUMBER 1.e+300
// Additional variables
int its; // Iteration counter
double a, ap; // Argument in series
// expansion.
double alpha, sig0, u; // Temporary quantities
double c0, c1, c2, c3, c4, c5x3, // Series coefficents
s1, s2, s3;
double psin, psip; // Acceptance bounds for
// sol. psi to Kep. eq.
double dtau,dtaun, dtaup; // Residuals in Newton
// method for solving
// Kep. eq.
double fm1, g; // f,g &
double fd, gdm1; // fdot, gdot express.
double mu , // Local copies of i/o
psi , // variables
r , r0 ,
s[6] , s0[6] ,
tau;
int loopexit; // Flag to exit main
// program loop.
int i,j,m;
// Copy the input pos, vel, tau, psi into
// local variables.
for (i=0; i<6 ; i++)
s0[i] = in->s0[i];
mu = in->mu;
tau = in->tau;
psi = in->psi;
// Compute initial orbit radius
r0 = sqrt(SQ(s0[0]) + SQ(s0[1]) + SQ(s0[2]));
// Compute other intermediate quantities.
sig0 = s0[0]*s0[3] + s0[1]*s0[4] + s0[2]*s0[5];
alpha = SQ(s0[3]) + SQ(s0[4]) + SQ(s0[5]) - 2*mu/r0;
// Initialize series mod count m to zero
m = 0;
//---Establish initial psi and initial acceptance bounds
//---for psi.
if (tau == 0) { // If input tau = 0, set
psi = 0; // output psi to 0; else
} else { // initialize acceptance
if (tau < 0) { // bounds for psi, and
psin = -LARGENUMBER; // initialize Newton
psip = 0; // method iteration
dtaun = psin; // residuals.
dtaup = -tau;
} else { //tau > 0
psin = 0;
psip = LARGENUMBER;
dtaun = -tau;
dtaup = psip;
}
// If the input psi lies between bounds
// psin and psip, use it as a first approx.
// to a solution of Kepler's equation.
// If not, we adjust the input psi before using
// it to solve Kepler.
if (!( (psi > psin) && (psi < psip)) ) {
// Try Newton's method for initial psi set equal to zero
psi = tau/r0;
// Set psi = tau if Newton's method fails
if (psi <= psin || psi >= psip)
psi = tau;
}
}
//---
loopexit = 0;
its = 0;
//----- BEGINNING OF LOOP FOR SOLVING GENERALIZED KEP. EQ.
do {
its++;
a = alpha * psi * psi;
if (fabs(a) > 1) {
ap = a; // Save original value of a
// Iterate until abs(a) <= 1.
while (fabs(a) > 1) {
m++; // Keep track of number of
// times reduce a.
a *= 0.25;
}
}
// Now compute "C series" terms:
// Note that they are functions of psi.
c5x3 = (1+(1+(1+(1+(1+(1+(1+a/342)*a/272)*a/210)*a/156)
*a/110)*a/72)*a/42)/40;
c4 = (1+(1+(1+(1+(1+(1+(1+a/306)*a/240)*a/182)*a/132)
*a/90)*a/56)*a/30)/24;
c3 = (.5 + a*c5x3)/3;
c2 = (.5 + a*c4);
c1 = 1 + a*c3;
c0 = 1 + a*c2;
// If we reduced "a" above, we have to adjust the
// C terms just computed.
if (m>0) {
while (m>0) {
c1 = c1*c0;
c0 = 2*c0*c0 - 1;
m--;
}
c2 = (c0 - 1)/ap;
c3 = (c1 - 1)/ap;
c4 = (c2 - .5)/ap;
c5x3 = (3 * c3-.5)/ap;
}
// Now use the C terms to compute the "S series" terms.
s1 = c1 * psi;
s2 = c2 * psi * psi;
s3 = c3 * psi * psi * psi;
g = r0*s1 + sig0*s2; // Compute g; used later to
// get position.
// Compute dtau, the function to be zeroed by the
// Newton method.
dtau = (g + mu*s3) - tau;
// r is the derivative of dtau with respect to psi.
r = fabs(r0*c0 + (sig0*s1 + mu*s2));
// Check for convergence of iteration and
// reset bounds for psi.
if (dtau == 0) {
loopexit = 1;
continue; // Get out of loop if dtau==0.
}
else if (dtau < 0) {
psin = psi;
dtaun = dtau;
}
else { // dtau > 0
psip = psi;
dtaup = dtau;
}
// This is the Newton step:
// x(n+1) = x(n) - y(n)/(dy/dx).
psi = psi - dtau/r;
// Accept psi for further iterations if it is
// between bounds psin and psip.
if ( (psi > psin) && (psi < psip) ) continue;
//-- -- -- Begin modifications to Newton method.
// Try incrementing bound with dtau nearest zero by
// the ratio 4*dtau/tau.
if ( fabs(dtaun) < fabs(dtaup) )
psi = psin * (1 - (4*dtaun)/tau);
if ( fabs(dtaup) < fabs(dtaun) )
psi = psip * (1 - (4*dtaup)/tau);
if ( (psi > psin) && (psi < psip) ) continue;
// Try doubling bound closest to zero.
if (tau > 0)
psi = psin + psin;
if (tau < 0)
psi = psip + psip;
if ( (psi > psin) && (psi < psip) ) continue;
// Try interpolation between bounds.
psi = psin + (psip - psin) * (-dtaun/(dtaup - dtaun));
if ( (psi > psin) && (psi < psip) ) continue;
// Try halving between bounds.
psi = psin + (psip - psin) * .5;
if ( (psi > psin) && (psi < psip) ) continue;
//-- -- --
// If we still are not between bounds, we've improved
// the estimate of psi as much as possible.
loopexit = 1;
} while ( loopexit == 0 && its <= 10);
//----- END OF LOOP FOR SOLVING GENERALIZED KEPLER EQ.
// Compute remaining three of four functions fm1, g, fd,
// gdm1
fm1 = -mu * s2 / r0;
fd = -mu * s1 / ( r0 * r);
gdm1 = -mu * s2 / r;
// Compute output solution for time t = t0 + tau
for (i=0;i<3;i++) {
// Position solution at time t
out->s[i] = s[i] = s0[i] + (fm1 * s0[i] + g * s0[i+3]);
// Velocity solution at time t
out->s[i+3] = s[i+3] = (fd * s0[i] + gdm1 * s0[i+3])
+ s0[i+3];
// Generalized eccentric anomaly for time t
in->psi = psi;
}
return(0);
}
SAMPLE INPUT/OUTPUT
The same pos/and vel was input for four
different values of tau.
Input:
X 6640.32 Y 0.00 Z 0.00
XD 0.00 YD 7.03 ZD 4.06
tau = 1576.78 sec = 1/4 orbit period
Output:
X -1470.76 Y 632